import tensorflow
from keras import layers, models

# 1.构建CNN网络
model_1 = models.Sequential()
model_1.add(layers.Conv2D(32, (3,3), activation ='relu',input_shape=(150, 150, 3)))
model_1.add(layers.MaxPooling2D(2, 2))
model_1.add(layers.Conv2D(64, (3,3), activation='relu'))
model_1.add(layers.MaxPooling2D(2,2))
model_1.add(layers.Conv2D(128, (3,3), activation='relu'))
model_1.add(layers.MaxPooling2D(2,2))
model_1.add(layers.Conv2D(128, (3,3), activation='relu'))
model_1.add(layers.MaxPooling2D(2,2))
model_1.add(layers.Flatten())
#使用数据增强来训练CNN
model_1.add(layers.Dropout(0.5))
model_1.add(layers.Dense(512, activation='relu'))
model_1.add(layers.Dense(1, activation='sigmoid'))
# 查看构建的网络结构
from tensorflow.keras.utils import plot_model
plot_model(model_1, show_shapes=True, to_file='model2_cats vs dogs.png')
#查看网络中的参数
model_1.summary()

#2.配置网络模型用于训练
from tensorflow import optimizers
model_1.compile(loss='binary_crossentropy',
                optimizer=optimizers.RMSprop(learning_rate=1e-4),
                metrics=['accuracy'])
# 3.数据预处理
from tensorflow.keras.preprocessing.image import ImageDataGenerator
#使用数据增强(在训练集上做数据增强，测试集上不需要）
train_datagen = ImageDataGenerator(rescale=1.0/255,
                                   rotation_range=40,  #角度值（在 0~180 范围内），表示图像随机旋转的角度范围
                                   width_shift_range=0.2, #图像在水平或垂直方向上平移的范围（相对于总宽度或总高度的比例）
                                   height_shift_range=0.2,
                                   shear_range=0.2, #是随机错切变换的角度
                                   zoom_range=0.2, #是图像随机缩放的范围
                                   horizontal_flip=0.2)  #是随机将一半图像水平翻转
test_datagen = ImageDataGenerator(rescale=1.0/255)

train_generator = train_datagen.flow_from_directory('./train_dataset/train/train',target_size=(150, 150),
                                                    batch_size=20,class_mode='binary')
validation_generator = test_datagen.flow_from_directory('./train_dataset/train/validation',target_size=(150,150),
                                                        batch_size=20, class_mode='binary')

#4.利用批量生成器拟合模型  ---利用数量增强生成器训练CNN
history = model_1.fit_generator(train_generator,
                                steps_per_epoch=100,
                                epochs=30,
                                validation_data=validation_generator,
                                validation_steps=50)
#保存模型
model_1.save('./model_data/model2_cats_vs_dogs_1.h5')

#5. 绘制训练过程中的损失曲线和精度曲线
import  matplotlib.pyplot as plt

accuracy = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(accuracy))

plt.plot(epochs, accuracy, 'bo')
plt.plot(epochs, accuracy, 'b', label='Training acc')
plt.plot(epochs,val_acc, 'ro')
plt.plot(epochs, val_acc, 'r', label='Validation acc')
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()
plt.plot(epochs, loss, 'bo')
plt.plot(epochs, loss,'b', label ='Training Loss')
plt.plot(epochs, val_loss,'ro')
plt.plot(epochs, val_loss,'r',label='Validation Loss')

plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.title("Training Loss and Validation Loss")
plt.legend()
plt.show()
